module W5200(
	clk,
	clk_100,
	rst_n,
	config_d,
	config_a,
	config_e,
	config_o,
	INT,
	rden,
	addro,
	datao,
	nCS,
	SCLK,
	MOSI,
	MISO
	);
	
	input				clk;
	input				clk_100;
	input				rst_n;
	input	[7:0]		config_d;
	input	[11:0]		config_a;
	input				config_e;
	input				config_o;
	input				INT;
	output				rden;
	output	[15:0]		addro;
	output	[7:0]		datao;
	
	output				nCS;
	output				SCLK;
	output				MOSI;
	input				MISO;
//**********************上电配置********************
wire			[10:0]	con_addr;
assign		con_addr	=	{config_a[11:9],config_a[7:0]};
reg				[7:0]	cf_data;
reg				[15:0]	cf_addr;
reg						cf_wren;
always@(posedge clk)	
begin
if(config_e)
begin
	cf_data	<=	config_d;
	if(con_addr<16'h0040)	
	begin
	cf_addr	<=	con_addr;
	cf_wren	<=	1;
	end
	else if(con_addr<16'h0070)
	begin
	cf_addr	<=	con_addr-16'h0040+16'h4000;
	cf_wren	<=	1;
	end
	else
	begin
	cf_addr	<=	cf_addr;
	cf_wren	<=	0;
	end	
end
else
begin
	cf_data	<=	cf_data;
	cf_addr	<=	cf_addr;
	cf_wren	<=	0;
end
end
//*******************end-上电配置*******************	
/*
上电配置默认IP 192.168.1.2 端口1108
*/
//**********************W5200状态机********************
reg			[15:0]		init_timer;
reg			[15:0]		addr;
reg			[15:0]		length;
reg						w;
reg			[7:0]		data;
reg						r;

reg			[3:0]		Status;
reg			[3:0]		main_state;
reg			[15:0]		Idle_cnt;
parameter
	Idle		    =4'h0,
	Read		    =4'h1,
	Open			=4'h2,
	Listen			=4'h3,
	Establishment	=4'h4,	
	ReadyRecv		=4'h5,		
	Recv			=4'h6,
	Readysend		=4'h7,
	Send			=4'h8,
	Over			=4'h9;

always@(posedge clk)
begin
if (config_o) 
	begin
	init_timer	<=	16'h0000;
	main_state	<=	Idle;
	end
else //if(init_timer	<	16'h1FFF)
	begin
		if(init_timer	<	16'h2000)
		init_timer	<=	init_timer	+	1;
		else
		init_timer	<=	init_timer;
		
		if(init_timer	<	16'h2000)
			begin
			if(init_timer[5:0]==6'h00)
				case(init_timer[15:6])
				10'h000:begin addr<=16'h0000;length<=16'h003F;w<=0;data<=8'h00;r<=1;end//	读通用寄存器
				10'h010:begin addr<=16'h4000;length<=16'h002F;w<=0;data<=8'h00;r<=1;end//	读socket寄存器
				10'h020:begin addr<=16'h4001;length<=16'h8001;w<=open_tcp;data<=8'h01;r<=0;end//	打开 TCP
				10'h021:begin addr<=16'h4001;length<=16'h8001;w<=open_tcp;data<=8'h02;r<=0;end//	LISTEN		
				10'h030:begin addr<=16'h0000;length<=16'h003F;w<=0;data<=8'h00;r<=1;end//	读通用寄存器
				10'h040:begin addr<=16'h4000;length<=16'h002F;w<=0;data<=8'h00;r<=1;end//	读socket寄存器		
				//10'h038:begin addr<=16'h402C;length<=16'h8001;w<=Sn_Listen;data<=8'hFF;r<=0;end//	LISTEN		
				//10'h040:begin addr<=16'hC000;length<=16'h003F;w<=0;data<=8'h00;r<=1;end//	读RX	
				//10'h05F:begin addr<=16'h4001;length<=16'h8001;w<=1;data<=8'h40;r<=0;end//	Sn_CR	=	RECV		
				//10'h060:begin addr<=16'h8000;length<=16'h803F;w<=1;data<=8'h00;r<=0;end//	写TX memory	
				//10'h07F:begin addr<=16'h4001;length<=16'h8001;w<=1;data<=8'h20;r<=0;end//	Sn_CR	=	RECV
				default:begin addr<=addr;length<=length;w<=0;data<=data;r<=0;end
				endcase 
			else	begin addr<=addr;length<=length;w<=0;data<=data;r<=0;end
			end
		
		else
			begin
			case(main_state)
			Idle:
				begin
					if(open_tcp)
						begin
						main_state<=Open;
						addr<=16'h4001;length<=16'h8001;w<=open_tcp;data<=8'h01;r<=0;//	打开 TCP
						end
					else if(INT_irp)
						begin 
						main_state<=Read;
						addr<=16'h4000;length<=16'h002F;w<=0;data<=8'h00;r<=1;//	读socket寄存器
						end
					else if(Idle_cnt==16'hFFFF)
						begin 
						main_state<=Read;
						addr<=16'h4000;length<=16'h002F;w<=0;data<=8'h00;r<=1;//	读socket寄存器
						end						
					else
						begin 
						Idle_cnt	<=	Idle_cnt+1;
						main_state	<=Idle;
						addr<=addr;length<=length;w<=0;data<=data;r<=0;
						end				
				end
			Open:
				begin
				if(ack)//已打开 TCP
				begin
					main_state<=Listen;
					addr<=16'h4001;length<=16'h8001;w<=open_tcp;data<=8'h02;r<=0;//	LISTEN
				end
				else
				begin 
					main_state<=main_state;
					addr<=addr;length<=length;w<=0;data<=data;r<=0;
				end							
				end
			Listen:	
				begin
				if(ack)//已打开 LISTEN
				begin
					main_state<=Listen;
					addr<=16'h4001;length<=16'h8001;w<=open_tcp;data<=8'h02;r<=0;//	LISTEN
				end
				else
				begin 
					main_state<=main_state;
					addr<=addr;length<=length;w<=0;data<=data;r<=0;
				end	
				end		
			Establishment:	
				begin
				
				end	
				
				
			ReadyRecv:	
				begin
				
				end			
			Recv:	
				begin
				
				end		
			Readysend:	
				begin
				
				end	
			Send:	
				begin
				
				end		
			Over:	
				begin
				
				end		
			
			Read:
				begin				
				if(ack)
				begin 
					main_state<=Read;
					addr<=addr;length<=length;w<=0;data<=data;r<=0;
				end
				else
				begin 
					main_state<=Read;
					addr<=addr;length<=length;w<=0;data<=data;r<=0;
				end
				
				end
			end
			
	end
//else		begin addr<=16'h0000;length<=16'h0000;w<=0;data<=8'h00;r<=0;end
end
//**********************************************************
//**************************W5200 内部寄存器状态********************************
reg		[7:0]	IR;
reg		[7:0]	IR2;
reg		[7:0]	IMR;
reg		[7:0]	IMR2;
reg		[7:0]	Sn_MR;
reg		[7:0]	Sn_CR;
reg		[7:0]	Sn_IR;
reg		[7:0]	Sn_SR;
reg		[7:0]	Sn_TX_FSR0;
reg		[7:0]	Sn_TX_FSR1;
reg		[7:0]	Sn_TX_RD0;
reg		[7:0]	Sn_TX_RD1;
reg		[7:0]	Sn_TX_WR0;
reg		[7:0]	Sn_TX_WR1;
reg		[7:0]	Sn_RX_RSR0;
reg		[7:0]	Sn_RX_RSR1;
reg		[7:0]	Sn_RX_RD0;
reg		[7:0]	Sn_RX_RD1;
reg		[7:0]	Sn_RX_WR0;
reg		[7:0]	Sn_RX_WR1;

//parameter 	OPEN	=	8'h01;
//parameter 	LISTEN	=	8'h02;
//parameter 	SEND	=	8'h20;
//parameter 	RECV	=	8'h40;
//parameter 	CLOSED	=	8'h00;
always@(posedge clk)
begin
if(rden)
case(addro)
16'h0015:	IR			<=	datao;
16'h0034:	IR2			<=	datao;
16'h0036:	IMR			<=	datao;
16'h0016:	IMR2		<=	datao;
16'h4000:	Sn_MR		<=	datao;
16'h4001:	Sn_CR		<=	datao;
16'h4002:	Sn_IR		<=	datao;
16'h4003:	Sn_SR		<=	datao;
16'h4020:	Sn_TX_FSR0	<=	datao;
16'h4021:	Sn_TX_FSR1	<=	datao;
16'h4022:	Sn_TX_RD0	<=	datao;
16'h4023:	Sn_TX_RD1	<=	datao;
16'h4024:	Sn_TX_WR0	<=	datao;
16'h4025:	Sn_TX_WR1	<=	datao;
16'h4026:	Sn_RX_RSR0	<=	datao;
16'h4027:	Sn_RX_RSR1	<=	datao;
16'h4028:	Sn_RX_RD0	<=	datao;
16'h4029:	Sn_RX_RD1	<=	datao;
16'h402A:	Sn_RX_WR0	<=	datao;
16'h402B:	Sn_RX_WR1	<=	datao;
endcase
end
reg				open_tcp;
reg				Sn_Listen;
reg				INT1;
reg				INT_irp;

always@(posedge clk)
begin
if(Sn_SR==8'h00)	//状态寄存器 00 SOCK_CLOSED Sn关闭时
open_tcp	<=	1;
else
open_tcp	<=	0;

if(Sn_IR==8'h01)
Sn_Listen	<=	1;
else
Sn_Listen	<=	0;

INT1	<=	INT;
if((INT1==1)&(INT==0))//INT低电平 中断
INT_irp		<=	1;
else
INT_irp		<=	0;
end
//**************************************************************************************
//**********************CMD SEL********************
reg		[15:0]	wraddr;
reg		[15:0]	wrlength;
reg				wr;
reg		[7:0]	datai;
reg				rd;	
always@(posedge clk)
begin
if(config_o)
begin
wraddr		<=	cf_addr;
wrlength	<=	16'h8001;
wr			<=	cf_wren;
datai		<=	cf_data;
rd			<=	0;
end
else
begin
wraddr		<=	addr;
wrlength	<=	length;
wr			<=	w;
datai		<=	data;
rd			<=	r;
end
end
//*************************************************

wire			ack;
SPI		WR_SPI(
		.clk(clk),
		.clk_100(clk_100),
		.rst_n(rst_n),

		.wraddr(wraddr),
		.wrlength(wrlength),
		.wr(wr),
		.addri(addri),
		.datai(datai),
		.rd(rd),
		.rden(rden),
		.addro(addro),
		.datao(datao),
		.ack(ack),
		.nCS(nCS),
		.SCLK(SCLK),
		.MOSI(MOSI),
		.MISO(MISO)
);
/* MODE register values */
parameter MR_RST			=8'h80; /**< reset */
parameter MR_WOL			=8'h20; /**< Wake on Lan */
parameter MR_PB				=8'h10; /**< ping block */
parameter MR_PPPOE			=8'h08; /**< enable pppoe */
parameter MR_LB  		    =8'h04; /**< little or big endian selector in indirect mode */
parameter MR_AI				=8'h02; /**< auto-increment in indirect mode */
parameter MR_IND			=8'h01; /**< enable indirect mode */

/* IR register values */
parameter IR_CONFLICT	    =8'h80; /**< check ip confict */
parameter IR_UNREACH	    =8'h40; /**< get the destination unreachable message in UDP sending */
parameter IR_PPPoE			=8'h20; /**< get the PPPoE close message */
parameter IR_MAGIC			=8'h10; /**< get the magic packet interrupt */
parameter IR_SOCK0	    	=8'h01; /**< check socket interrupt */
parameter IR_SOCK1	    	=8'h02;
parameter IR_SOCK2	    	=8'h04;
parameter IR_SOCK3	    	=8'h08;
parameter IR_SOCK4	    	=8'h10;
parameter IR_SOCK5	    	=8'h20;
parameter IR_SOCK6	    	=8'h40;
parameter IR_SOCK7	    	=8'h80;

/* Sn_MR values */
parameter Sn_MR_CLOSE		=8'h00;		/**< unused socket */
parameter Sn_MR_TCP			=8'h01;		/**< TCP */
parameter Sn_MR_UDP			=8'h02;		/**< UDP */
parameter Sn_MR_IPRAW	    =8'h03;		/**< IP LAYER RAW SOCK */
parameter Sn_MR_MACRAW		=8'h04;		/**< MAC LAYER RAW SOCK */
parameter Sn_MR_PPPOE		=8'h05;		/**< PPPoE */
parameter Sn_MR_ND			=8'h20;		/**< No Delayed Ack(TCP) flag */
parameter Sn_MR_MULTI		=8'h80;		/**< support multicating */

/* Sn_CR values */
parameter Sn_CR_OPEN		=8'h01;		/**< initialize or open socket */
parameter Sn_CR_LISTEN		=8'h02;		/**< wait connection request in tcp mode(Server mode) */
parameter Sn_CR_CONNECT		=8'h04;		/**< send connection request in tcp mode(Client mode) */
parameter Sn_CR_DISCON		=8'h08;		/**< send closing reqeuset in tcp mode */
parameter Sn_CR_CLOSE		=8'h10;		/**< close socket */
parameter Sn_CR_SEND		=8'h20;		/**< update txbuf pointer, send data */
parameter Sn_CR_SEND_MAC	=8'h21;		/**< send data with MAC address, so without ARP process */
parameter Sn_CR_SEND_KEEP 	=8'h22;		/**<  send keep alive message */
parameter Sn_CR_RECV		=8'h40;		/**< update rxbuf pointer, recv data */


parameter Sn_CR_PCON		=8'h23;
parameter Sn_CR_PDISCON		=8'h24;
parameter Sn_CR_PCR			=8'h25;
parameter Sn_CR_PCN			=8'h26;
parameter Sn_CR_PCJ			=8'h27;
/* Sn_IR values */

parameter Sn_IR_PRECV		=8'h80;
parameter Sn_IR_PFAIL		=8'h40;
parameter Sn_IR_PNEXT		=8'h20;
;
parameter Sn_IR_SEND_OK			=8'h10;		/**< complete sending */
parameter Sn_IR_TIMEOUT			=8'h08;		/**< assert timeout */
parameter Sn_IR_RECV			=8'h04;		/**< receiving data */
parameter Sn_IR_DISCON			=8'h02;		/**< closed socket */
parameter Sn_IR_CON				=8'h01;		/**< established connection */

/* Sn_SR values */
parameter SOCK_CLOSED			=8'h00;		/**< closed */
parameter SOCK_INIT 			=8'h13;		/**< init state */
parameter SOCK_LISTEN			=8'h14;		/**< listen state */
parameter SOCK_SYNSENT	   		=8'h15;		/**< connection state */
parameter SOCK_SYNRECV		   	=8'h16;		/**< connection state */
parameter SOCK_ESTABLISHED		=8'h17;		/**< success to connect */
parameter SOCK_FIN_WAIT			=8'h18;		/**< closing state */
parameter SOCK_CLOSING		   	=8'h1A;		/**< closing state */
parameter SOCK_TIME_WAIT		=8'h1B;		/**< closing state */
parameter SOCK_CLOSE_WAIT		=8'h1C;		/**< closing state */
parameter SOCK_LAST_ACK			=8'h1D;		/**< closing state */
parameter SOCK_UDP				=8'h22;		/**< udp socket */
parameter SOCK_IPRAW			=8'h32;		/**< ip raw mode socket */
parameter SOCK_MACRAW			=8'h42;		/**< mac raw mode socket */
parameter SOCK_PPPOE			=8'h5F;		/**< pppoe socket */

/* IP PROTOCOL */
parameter IPPROTO_IP              =8'd0;           /**< Dummy for IP */
parameter IPPROTO_ICMP            =8'd1;           /**< Control message protocol */
parameter IPPROTO_IGMP            =8'd2;         /**< Internet group management protocol */
parameter IPPROTO_GGP             =8'd3;         /**< Gateway^2 (deprecated) */
parameter IPPROTO_TCP             =8'd6;           /**< TCP */
parameter IPPROTO_PUP             =8'd12;          /**< PUP */
parameter IPPROTO_UDP             =8'd17;          /**< UDP */
parameter IPPROTO_IDP             =8'd22;          /**< XNS idp */
parameter IPPROTO_ND              =8'd77;          /**< UNOFFICIAL net disk protocol */
parameter IPPROTO_RAW             =8'd255;         /**< Raw IP packet */

endmodule 